using System;
using System.IO.Ports;
using System.Collections.Generic;
using System.Text;
using Fornax020.SerialComm.Configuration;
using Fornax020.SerialComm.Protocol;

namespace Fornax020.SerialComm.Core
{
    /// <summary>
    /// 串口通信管理器 - 负责所有串口通信相关的操作
    /// 设计模式应用：
    /// 1. 单一职责原则：专门负责串口通信，不处理UI逻辑
    /// 2. 观察者模式：通过事件通知UI层数据变化
    /// 3. 策略模式：可扩展的数据解析策略
    /// </summary>
    public class SerialManager : IDisposable
    {
        #region 私有字段
        private SerialPort _serialPort;
        private bool _isConnected = false;
        private List<byte> _receiveBuffer = new List<byte>();
        private readonly SerialConfig _config;
        private readonly object _lockObject = new object();

        #endregion

        #region 事件定义
        /// <summary>
        /// 数据接收事件
        /// </summary>
        public event EventHandler<DataReceivedEventArgs> DataReceived;

        /// <summary>
        /// 连接状态变化事件
        /// </summary>
        public event EventHandler<ConnectionStatusEventArgs> ConnectionStatusChanged;

        /// <summary>
        /// 错误发生事件
        /// </summary>
        public event EventHandler<ErrorEventArgs> ErrorOccurred;

        #endregion

        #region 构造函数
        /// <summary>
        /// 默认构造函数 - 使用默认配置
        /// </summary>
        public SerialManager() : this(SerialConfig.Default)
        {
        }

        /// <summary>
        /// 带配置的构造函数
        /// </summary>
        /// <param name="config">串口配置</param>
        public SerialManager(SerialConfig config)
        {
            _config = config ?? throw new ArgumentNullException(nameof(config));
        }

        #endregion

        #region 公共属性
        /// <summary>
        /// 是否已连接
        /// </summary>
        public bool IsConnected
        {
            get
            {
                lock (_lockObject)
                {
                    return _isConnected && _serialPort != null && _serialPort.IsOpen;
                }
            }
        }

        /// <summary>
        /// 当前连接的端口名称
        /// </summary>
        public string PortName => _serialPort?.PortName ?? string.Empty;

        /// <summary>
        /// 当前波特率
        /// </summary>
        public int BaudRate => _serialPort?.BaudRate ?? 0;

        #endregion

        #region 连接管理
        /// <summary>
        /// 连接到串口设备
        /// </summary>
        /// <param name="portName">端口名称，如"COM3"</param>
        /// <param name="baudRate">波特率，默认9600</param>
        /// <returns>连接是否成功</returns>
        public bool Connect(string portName = null, int? baudRate = null)
        {
            try
            {
                lock (_lockObject)
                {
                    // 如果已经连接，先断开
                    if (_isConnected)
                    {
                        Disconnect();
                    }

                    // 使用参数或配置中的默认值
                    string actualPortName = portName ?? _config.DefaultPort;
                    int actualBaudRate = baudRate ?? _config.DefaultBaudRate;

                    // 创建串口对象
                    _serialPort = new SerialPort(actualPortName, actualBaudRate)
                    {
                        DataBits = _config.DataBits,
                        StopBits = _config.StopBits,
                        Parity = _config.Parity,
                        Handshake = _config.Handshake,
                        ReadTimeout = _config.ReadTimeout,
                        WriteTimeout = _config.WriteTimeout
                    };

                    // 订阅数据接收事件
                    _serialPort.DataReceived += OnSerialDataReceived;

                    // 打开串口
                    _serialPort.Open();
                    _isConnected = true;

                    // 清空接收缓冲区
                    _receiveBuffer.Clear();

                    // 触发连接状态变化事件
                    OnConnectionStatusChanged(true, $"已连接到 {actualPortName}");

                    return true;
                }
            }
            catch (Exception ex)
            {
                OnErrorOccurred($"连接失败: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 断开串口连接
        /// </summary>
        public void Disconnect()
        {
            try
            {
                lock (_lockObject)
                {
                    if (_serialPort != null)
                    {
                        // 取消订阅事件
                        _serialPort.DataReceived -= OnSerialDataReceived;

                        // 关闭串口
                        if (_serialPort.IsOpen)
                        {
                            _serialPort.Close();
                        }

                        _serialPort.Dispose();
                        _serialPort = null;
                    }

                    _isConnected = false;
                    _receiveBuffer.Clear();

                    // 触发连接状态变化事件
                    OnConnectionStatusChanged(false, "已断开连接");
                }
            }
            catch (Exception ex)
            {
                OnErrorOccurred($"断开连接时发生错误: {ex.Message}");
            }
        }

        #endregion

        #region 数据发送
        /// <summary>
        /// 发送字节数组数据
        /// </summary>
        /// <param name="data">要发送的数据</param>
        /// <returns>发送是否成功</returns>
        public bool SendData(byte[] data)
        {
            if (!IsConnected || data == null || data.Length == 0)
            {
                return false;
            }

            try
            {
                lock (_lockObject)
                {
                    System.Diagnostics.Debug.WriteLine($"[SerialManager] 发送数据: {BitConverter.ToString(data)} (长度: {data.Length})");
                    _serialPort.Write(data, 0, data.Length);
                    System.Diagnostics.Debug.WriteLine($"[SerialManager] 数据发送成功");
                    return true;
                }
            }
            catch (Exception ex)
            {
                OnErrorOccurred($"发送数据失败: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 发送字符串数据
        /// </summary>
        /// <param name="data">要发送的字符串</param>
        /// <returns>发送是否成功</returns>
        public bool SendData(string data)
        {
            if (string.IsNullOrEmpty(data))
            {
                return false;
            }

            byte[] bytes = Encoding.UTF8.GetBytes(data);
            return SendData(bytes);
        }

        #endregion

        #region 数据接收处理
        /// <summary>
        /// 串口数据接收事件处理
        /// </summary>
        private void OnSerialDataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                lock (_lockObject)
                {
                    if (_serialPort == null || !_serialPort.IsOpen)
                        return;

                    // 一次性读取所有可用数据
                    int bytesToRead = _serialPort.BytesToRead;
                    System.Diagnostics.Debug.WriteLine($"[SerialManager] 串口数据接收事件触发，可读字节数: {bytesToRead}");
                    
                    if (bytesToRead > 0)
                    {
                        byte[] buffer = new byte[bytesToRead];
                        int bytesRead = _serialPort.Read(buffer, 0, bytesToRead);
                        System.Diagnostics.Debug.WriteLine($"[SerialManager] 读取到 {bytesRead} 字节: {BitConverter.ToString(buffer)}");

                        // 添加到接收缓冲区
                        for (int i = 0; i < bytesRead; i++)
                        {
                            _receiveBuffer.Add(buffer[i]);
                        }

                        System.Diagnostics.Debug.WriteLine($"[SerialManager] 缓冲区总大小: {_receiveBuffer.Count}");
                        System.Diagnostics.Debug.WriteLine($"[SerialManager] 缓冲区内容: {BitConverter.ToString(_receiveBuffer.ToArray())}");

                        // 处理完整的数据包
                        ProcessReceivedData();
                    }
                }
            }
            catch (Exception ex)
            {
                OnErrorOccurred($"接收数据时发生错误: {ex.Message}");
            }
        }

        /// <summary>
        /// 处理接收到的数据 - 正确的帧解析逻辑
        /// </summary>
        private void ProcessReceivedData()
        {
            System.Diagnostics.Debug.WriteLine($"[SerialManager] 处理接收数据，缓冲区大小: {_receiveBuffer.Count}");
            
            if (_receiveBuffer.Count == 0)
                return;
                
            // 逐个字节解析，查找完整的帧
            int frameStart = -1;
            int frameEnd = -1;
            
            for (int i = 0; i < _receiveBuffer.Count; i++)
            {
                byte currentByte = _receiveBuffer[i];
                
                // 查找帧头 (STX)
                if (currentByte == (byte)ProtocolConstants.STX)
                {
                    frameStart = i;
                    System.Diagnostics.Debug.WriteLine($"[SerialManager] 找到帧头STX，位置: {i}");
                }
                // 查找帧尾 (CR或空字节)
                else if ((currentByte == (byte)ProtocolConstants.CR || currentByte == 0x00) && frameStart >= 0)
                {
                    frameEnd = i;
                    System.Diagnostics.Debug.WriteLine($"[SerialManager] 找到帧尾，位置: {i}, 字节: 0x{currentByte:X2}");
                    
                    // 提取完整帧
                    int frameLength = frameEnd - frameStart + 1;
                    byte[] frameData = new byte[frameLength];
                    
                    for (int j = 0; j < frameLength; j++)
                    {
                        frameData[j] = _receiveBuffer[frameStart + j];
                    }
                    
                    System.Diagnostics.Debug.WriteLine($"[SerialManager] 提取完整帧: {BitConverter.ToString(frameData)} (长度: {frameLength})");
                    
                    // 转换为字符串并触发事件
                    string dataString = Encoding.UTF8.GetString(frameData);
                    System.Diagnostics.Debug.WriteLine($"[SerialManager] 帧数据字符串: '{dataString}'");
                    OnDataReceived(dataString);
                    
                    // 移除已处理的帧数据
                    _receiveBuffer.RemoveRange(0, frameEnd + 1);
                    System.Diagnostics.Debug.WriteLine($"[SerialManager] 移除已处理数据，剩余缓冲区大小: {_receiveBuffer.Count}");
                    
                    // 递归处理剩余数据
                    ProcessReceivedData();
                    return;
                }
            }
            
            // 如果没有找到完整帧，检查缓冲区是否过大
            if (_receiveBuffer.Count > _config.BufferSize)
            {
                System.Diagnostics.Debug.WriteLine($"[SerialManager] 缓冲区过大({_receiveBuffer.Count} > {_config.BufferSize})，清空缓冲区");
                OnErrorOccurred("接收缓冲区溢出，清空缓冲区");
                _receiveBuffer.Clear();
            }
            else if (_receiveBuffer.Count > 0)
            {
                System.Diagnostics.Debug.WriteLine($"[SerialManager] 未找到完整帧，等待更多数据。当前缓冲区: {BitConverter.ToString(_receiveBuffer.ToArray())}");
            }
        }

        #endregion

        #region 事件触发方法
        /// <summary>
        /// 触发数据接收事件
        /// </summary>
        protected virtual void OnDataReceived(string data)
        {
            DataReceived?.Invoke(this, new DataReceivedEventArgs(data));
        }

        /// <summary>
        /// 触发连接状态变化事件
        /// </summary>
        protected virtual void OnConnectionStatusChanged(bool isConnected, string message)
        {
            ConnectionStatusChanged?.Invoke(this, new ConnectionStatusEventArgs(isConnected, message));
        }

        /// <summary>
        /// 触发错误事件
        /// </summary>
        protected virtual void OnErrorOccurred(string errorMessage)
        {
            ErrorOccurred?.Invoke(this, new ErrorEventArgs(errorMessage));
        }

        #endregion

        #region IDisposable实现
        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// 释放资源的具体实现
        /// </summary>
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                Disconnect();
            }
        }

        #endregion
    }
}
